package cn.bo.cloud.common.core.encrypt;

import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

/**
 * @author tao.hong
 */
public class RsaUtils {

    private static final String DEFAULT_PRIVATEKEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAJtM25/9Ag/SvmEi" +
            "oDHUsiZHvpSwmBgZE3dFhUFFcAYg1QO4rdX5IMuQm84DqAMPSSMflxNe52kHEpJT" +
            "9NJtEw918msV0zTZWiS/dYDRQK11X6XxxKBrrtAPyQdulo3H7fLVWRfwOfSk7Uv1" +
            "h22szV27ePkkNgbENQo+/5aIC1Y9AgMBAAECgYEAkJbhUDaGqebDW7qaPWrTJrLb" +
            "bKJyKNWH+x8d7uRQZVRCH0Hdj39wmjab6RYcYiTkKjBqPx24BGASWWyTXyswd1w6" +
            "hNbXLzM7KT78oKWmS8ju1GdZP8qZmrgzIJVpjSE0DumWMluccxbWsGnxMiZ5pc1J" +
            "jbOVU+ty5VRco/sAbAECQQDKq2xWORZkcUkSlQvAtF7De1Ex3deoUCAZq38JqrU1" +
            "z1t3j5ylmbC5NTTWlEh8nphqUUFoByC436Hp/k7nj809AkEAxCp06RRDj3Y0SfeY" +
            "5/TTPncrdd9YTVFmEOI1ZlWo460RSmP6ldpkScrudYsdvQDIO7KWGlxSXbBa/1x/" +
            "gCQ9AQJAfwgPscO6i16OhL0zTqg/tZt3+x+n6vG+DRj3WaHMT1wXYst7TjkVEiGN" +
            "auoqvSHTOuCPdJrzIa3amQYzguUZqQJBAJsgQAe5wJuIjF0Z8c8sqoixUKsMDhZG" +
            "koIzgKsGfmJdkFjVq2oppDk+w0gs1T2Lisy6szzxWSlBtxRNn35EKgECQQCCR3C1" +
            "M1QIFJkNSefzgyCukHmLAnSZNCEeFQ91L5462PWHt7V6Br5dmDg9NSmmuzsw3tZ5" +
            "Ju2xSS8SXzAZ2OnT";

    private static final String DEFAULT_PUBLICKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbTNuf/QIP0r5hIqAx1LImR76UsJgYGRN3RYVBRXAGINUDuK3V+SDLkJvOA6gDD0kjH5cTXudpBxKSU/" +
            "TSbRMPdfJrFdM02Vokv3WA0UCtdV+l8cSga67QD8kHbpaNx+3y1VkX8Dn0pO1L9YdtrM1du3j5JDYGxDUKPv+WiAtWPQIDAQAB";

//    private static Map<Integer, String> keyMap = new HashMap<Integer, String>();  //用于封装随机产生的公钥与私钥
//    public static void main(String[] args) throws Exception {
//        //生成公钥和私钥
//        genKeyPair();
//        //加密字符串
//        String message = "df723820";
//        System.out.println("随机生成的公钥为:" + keyMap.get(0));
//        System.out.println("随机生成的私钥为:" + keyMap.get(1));
//        String messageEn = encrypt(message,keyMap.get(0));
//        System.out.println(message + "\t加密后的字符串为:" + messageEn);
//        String messageDe = decrypt(messageEn,keyMap.get(1));
//        System.out.println("还原后的字符串为:" + messageDe);
//    }

//    /**
//     * 随机生成密钥对
//     * @throws NoSuchAlgorithmException
//     */
//    public static void genKeyPair() throws NoSuchAlgorithmException {
//        // KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
//        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
//        // 初始化密钥对生成器，密钥大小为96-1024位
//        keyPairGen.initialize(1024,new SecureRandom());
//        // 生成一个密钥对，保存在keyPair中
//        KeyPair keyPair = keyPairGen.generateKeyPair();
//        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥
//        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥
//        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
//        // 得到私钥字符串
//        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
//        // 将公钥和私钥保存到Map
//        keyMap.put(0,publicKeyString);  //0表示公钥
//        keyMap.put(1,privateKeyString);  //1表示私钥
//    }
    /**
     * RSA公钥加密
     *
     * @param str
     *            加密字符串
     * @return 密文
     * @throws Exception
     *             加密过程中的异常信息
     */
    public static String encryptByPublic(String keyStr, String str ) throws Exception{
        if (StringUtils.isEmpty(keyStr)) {
            keyStr = DEFAULT_PUBLICKEY;
        }
        //base64编码的公钥
        byte[] decoded = Base64.getDecoder().decode(keyStr);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }

    /**
     * RSA私钥加密
     *
     * @param str
     *            加密字符串
     * @return 密文
     * @throws Exception
     *             加密过程中的异常信息
     */
    public static String encryptByPrivate(String keyStr, String str) throws Exception{
        if (StringUtils.isEmpty(keyStr)) {
            keyStr = DEFAULT_PRIVATEKEY;
        }
        byte[] keyBytes = Base64.getDecoder().decode(keyStr);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory factory = KeyFactory.getInstance("RSA", "SunRsaSign");
        PrivateKey privateKey = factory.generatePrivate(spec);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        try {
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        } catch (InvalidKeyException e) {
            //For IBM JDK, 原因请看解密方法中的说明
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
            RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(rsaPrivateKey.getModulus(), rsaPrivateKey.getPrivateExponent());
            Key fakePublicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, fakePublicKey);
        }

        byte[] encryptedBytes = cipher.doFinal(str.getBytes("UTF-8"));
        String encryptedString = Base64.getEncoder().encodeToString(encryptedBytes);
        return encryptedString;
    }

    /**
     * RSA私钥解密
     *
     * @param str
     *            加密字符串
     * @return 铭文
     * @throws Exception
     *             解密过程中的异常信息
     */
    public static String decryptByPrivate(String keyStr, String str) throws Exception{
        if (StringUtils.isEmpty(keyStr)) {
            keyStr = DEFAULT_PRIVATEKEY;
        }
        //64位解码加密后的字符串
        byte[] inputByte = Base64.getDecoder().decode(str.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.getDecoder().decode(keyStr);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

    /**
     * 公钥解密
     * @param keyStr
     * @param cipherText
     * @return
     * @throws Exception
     */
    public static String decryptByPublic(String keyStr, String cipherText)
            throws Exception {
        if(StringUtils.isEmpty(keyStr)){
            keyStr = DEFAULT_PUBLICKEY;
        }
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        PublicKey publicKey = getPublicKey(keyStr);
        RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
        try {
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
        } catch (InvalidKeyException e) {
            // 因为 IBM JDK 不支持私钥加密, 公钥解密, 所以要反转公私钥
            // 也就是说对于解密, 可以通过公钥的参数伪造一个私钥对象欺骗 IBM JDK
            RSAPrivateKeySpec spec = new RSAPrivateKeySpec(rsaPublicKey.getModulus(), rsaPublicKey.getPublicExponent());
            Key fakePrivateKey = KeyFactory.getInstance("RSA").generatePrivate(spec);
            cipher = Cipher.getInstance("RSA"); //It is a stateful object. so we need to get new one.
            cipher.init(Cipher.DECRYPT_MODE, fakePrivateKey);
        }

        if (cipherText == null || cipherText.length() == 0) {
            return cipherText;
        }

        byte[] cipherBytes = Base64.getDecoder().decode(cipherText);
        byte[] plainBytes = cipher.doFinal(cipherBytes);

        return new String(plainBytes);
    }



    public static PublicKey getPublicKey(String publicKeyText) {
        try {
            byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyText);
            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(
                    publicKeyBytes);

            KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SunRsaSign");
            return keyFactory.generatePublic(x509KeySpec);
        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to get public key", e);
        }
    }

    public static void main(String[] args) throws Exception {
//        String decrypt = RsaUtils.decrypt("MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKHGwq7q2RmwuRgKxBypQHw0mYu4BQZ3eMsTrdK8E6igRcxsobUC7uT0SoxIjl1WveWniCASejoQtn/BY6hVKWsCAwEAAQ=="
//                ,"ki/UtjtCfEye+/zNPVj35u2qMjOA3Rr7l5dWUFvZe4x9z7dCguVZQww9cnRtVnWgniPXQQy9dzb+eomcpM1ifg==");
//        System.out.println(decrypt);
//        String encrypt = RsaUtils.encryptByPrivate("MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAocbCrurZGbC5GArEHKlAfDSZi7gFBnd4yxOt0rwTqKBFzGyhtQLu5PRKjEiOXVa95aeIIBJ6OhC2f8FjqFUpawIDAQABAkAPejKaBYHrwUqUEEOe8lpnB6lBAsQIUFnQI/vXU4MV+MhIzW0BLVZCiarIQqUXeOhThVWXKFt8GxCykrrUsQ6BAiEA4vMVxEHBovz1di3aozzFvSMdsjTcYRRo82hS5Ru2/OECIQC2fAPoXixVTVY7bNMeuxCP4954ZkXp7fEPDINCjcQDywIgcc8XLkkPcs3Jxk7uYofaXaPbg39wuJpEmzPIxi3k0OECIGubmdpOnin3HuCP/bbjbJLNNoUdGiEmFL5hDI4UdwAdAiEAtcAwbm08bKN7pwwvyqaCBC//VnEWaq39DCzxr+Z2EIk=", "wDNfzNGCMgTvAmIzjOU6wU2l5XBX7foL");
//        System.out.println(encrypt);
//        String decrypt = RsaUtils.decryptByPublic(MainConstants.PASSWORD_PUBLIC_KEY, encrypt);
//        System.out.println(decrypt);
//        System.out.println(decrypt.equals("wDNfzNGCMgTvAmIzjOU6wU2l5XBX7foL"));
    }
}
